#include "zrpc/base/thread.h"

#include "zrpc/net/event_loop.h"

namespace zrpc {
Thread::Thread(const ThreadInitCallback &cb)
    : loop_(nullptr), exiting_(false), callback_(std::move(cb)) {}

Thread::~Thread() { StopLoop(); }

void Thread::StopLoop() {
  if (loop_ && bg_thread_->joinable()) {
    loop_->Quit();
    bg_thread_->join();
  }
}

EventLoop *Thread::StartLoop() {
  bg_thread_.reset(new std::thread(std::bind(&Thread::ThreadFunc, this)));

  EventLoop *loop = nullptr;
  {
    std::unique_lock<std::mutex> lk(mutex_);
    while (loop_ == nullptr) {
      condition_.wait(lk);
    }
    loop = loop_;
  }
  return loop;
}

void Thread::ThreadFunc() {
  EventLoop loop;

  if (callback_) {
    callback_(&loop);
  }

  {
    std::unique_lock<std::mutex> lk(mutex_);
    loop_ = &loop;
    condition_.notify_one();
  }

  loop.Run();
}
}  // namespace zrpc